`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@file UticaCPURegisterFile.v
	@author Andrew D. Zonenberg
	@brief The register file
	
	Standard triple-ported design.
	
	Implements 16 windows despite the standard MIPS register file only supporting one.
	This is for future expansion into hardware multithreading.
	
	32 bits
		x 32 registers = 1 kbit
		x 16 windows = 16 kbit
		x 2 read ports = 2x 16kbit
	
	Implemented on a pair of 18kbit block RAMs.
 */
 
//Uncomment this line to enable printing of all register writes
//`define UTICA_TRACE_REG_WRITE
 
module UticaCPURegisterFile(
	clk,
	w_enable, w_window,  w_regid,  w_data,
	          ra_window, ra_regid, ra_data,
	          rb_window, rb_regid, rb_data
    );

	////////////////////////////////////////////////////////////////////////////////////////////////
	// Global stuff
	input wire clk;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Write port
	input wire w_enable;
	input wire[3:0] w_window;
	input wire[4:0] w_regid;
	input wire[31:0] w_data;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Read port A
	input wire[3:0] ra_window;
	input wire[4:0] ra_regid;
	output wire[31:0] ra_data;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Read port B
	input wire[3:0] rb_window;
	input wire[4:0] rb_regid;
	output wire[31:0] rb_data;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Debug logic (simulation only)
	`ifdef UTICA_TRACE_REG_WRITE
		always @(posedge clk) begin
			if(w_enable && w_regid != 0) begin
				$display("[UticaCPURegisterFile] Writing value 0x%x to $r%d of window %d",
					w_data, w_regid, w_window);
			end
		end
	`endif
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Forwarding logic
		
	wire[31:0] ra_data_raw;
	wire[31:0] rb_data_raw;
	
	// Disable memory read if we're writing to the same address we're reading from
	wire ra_forward;
	wire rb_forward;
	assign ra_forward = w_enable && ra_window == w_window && w_regid == ra_regid;
	assign rb_forward = w_enable && rb_window == w_window && w_regid == rb_regid;
	
	//Remember whether we should forward and, if so, what the value is
	reg ra_forward_buf = 0;
	reg rb_forward_buf = 0;
	reg[31:0] w_data_buf = 0;
	always @(posedge clk) begin
		ra_forward_buf <= ra_forward;
		rb_forward_buf <= rb_forward;
		w_data_buf <= w_data;
	end
	
	//Mux the forwarded and normal outputs
	assign ra_data = ra_forward_buf ? w_data_buf : ra_data_raw;
	assign rb_data = rb_forward_buf ? w_data_buf : rb_data_raw;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// The actual memory blocks
	BRAM_SDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.WRITE_WIDTH(32),
		.READ_WIDTH(32),
		.DO_REG(0),
		.INIT_FILE ("NONE"),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL(72'h000000000000000000),
		.INIT(72'h000000000000000000),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) porta_ram (
		.DO(ra_data_raw),
		.DI(w_data),
		.RDADDR({ra_window, ra_regid}),
		.RDCLK(clk),
		.RDEN(!ra_forward),	//do not read from a write address
		.REGCE(1'b1),
		.RST(1'b0),
		.WE({w_enable, w_enable, w_enable, w_enable}),	//byte write enable
		.WRADDR({w_window, w_regid}),
		.WRCLK(clk),
		.WREN(w_enable && (w_regid != 0))				//write port enable iff not writing to $r0
		);
		
	BRAM_SDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.WRITE_WIDTH(32),
		.READ_WIDTH(32),
		.DO_REG(0),
		.INIT_FILE ("NONE"),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL(72'h000000000000000000),
		.INIT(72'h000000000000000000),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) portb_ram (
		.DO(rb_data_raw),
		.DI(w_data),
		.RDADDR({rb_window, rb_regid}),
		.RDCLK(clk),
		.RDEN(!rb_forward),	//do not read from a write address
		.REGCE(1'b1),
		.RST(1'b0),
		.WE({w_enable, w_enable, w_enable, w_enable}),	//byte write enable
		.WRADDR({w_window, w_regid}),
		.WRCLK(clk),
		.WREN(w_enable && (w_regid != 0))				//write port enable iff not writing to $r0
		);

endmodule
